package com.tianhao.export.util;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @Date 2021/8/15
 * @Author tianhao.luo
 * @Description 支持按count总数进行拆分list集合，同时支持临界count位置处元素符合延续获取条件时，能继续获取符合延续条件的元素
 */
public class KnifeListSplitUtil {
    /**
     * 用来获取判断是否延续取集合元素的方法
     * @param <T> 参数来源对象
     * @param <R> 返回类型
     */
    public interface ContinueField<T, R> {
        R get(T t);
    }

    /**
     * 切割集合
     *
     * @param count 以多少个来进行切割
     * @param toDoList 待切割集合
     * @param comparator 看调用者是否需要对待排序集合进行排序
     * @param continueField 切割点是否要进行延续,例如:切割点是assetId=300的元素,
     *        如果集合中下一个元素的assetId仍然为300,是否需要把下一个元素放入本次切割的集合中
     * @param <T> 待切割集合类型
     * @param <R> ContinueField的返回值类型
     * @return 切割好的集合
     */
    public static  <T,R> List<List<T>> splitList(int count, List<T> toDoList, Comparator<T> comparator, ContinueField<T,R> continueField) {
        if (continueField !=null && comparator == null){
            throw new RuntimeException("如果切割集合时,需要考虑切割点元素符合continueField条件延续,那么必须要对集合排序");
        }
        // 因为子线程中不向该list中放数据,所以可以使用ArrayList
        ArrayList<List<T>> lists = new ArrayList<>();
        if (comparator != null) {
            toDoList.sort(comparator);
        }
        if (toDoList.size() > count) {
            // 切割list时,需要注意临界点的设备id数据必须一起切割
            int startIndex = 0;
            while (startIndex < toDoList.size()) {
                int maxEndIndex = startIndex + count;
                // 当本次预计结束位置超出了list长度时,取list的最后一个位置作为结束索引
                if (maxEndIndex >= toDoList.size()) {
                    maxEndIndex = toDoList.size() - 1;
                }
                T t = toDoList.get(maxEndIndex);
                while (maxEndIndex + 1 < toDoList.size() && continueField != null && continueField.get(t).equals(continueField.get(toDoList.get(maxEndIndex + 1)))) {
                    maxEndIndex++;
                }
                ArrayList<T> workOrders = new ArrayList<>();
                for (int i = startIndex; i <= maxEndIndex; i++) {
                    workOrders.add(toDoList.get(i));
                }
                lists.add(workOrders);
                // 更新起始位置
                startIndex = maxEndIndex + 1;
            }
        } else {
            lists.add(toDoList);
        }
        return lists;
    }


    /**
     * @description
     * @since 1.0
     * @version 1.0
     * @author tianhao.luo@hand-china.com
     * @date 2022/2/25 1:58 下午
     * @param list 集合数据
     * @param groupByIdFunction 分组操作
     * @param c 分组之后的，组内排序
     * @return 分组排序后的数据
     */
    public static <T,E> List<T> groupThenSortList(List<T> list, Function<T,E> groupByIdFunction,Comparator<? super E> e, Comparator<? super T> c){
        // 对同一个部门下的数据进行排序
        Map<E, List<T>> map = list.stream().collect(Collectors.groupingBy(groupByIdFunction));
        List<T> returnList = new ArrayList<>(list.size());
        // 按组织id升序排序
        Set<E> keySet = map.keySet();
        List<E> keyList = new ArrayList<>(keySet);
        keyList.sort(e);
        keyList.forEach(key->{
            List<T> value = map.get(key);
            value.sort(c);
            returnList.addAll(value);
        });
        return returnList;
    }
}
